<!DOCTYPE html>
<html lang="zh_cn">
<head>
          <title>来玩魔王的咚</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta charset="utf-8" />
        <!-- twitter card metadata -->
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="/images/mowang.png">
<meta name="twitter:site" content="">
<meta name="twitter:title" content="Terraform 基本用法">
<meta name="twitter:description" content="<p>Terraform的基本使用：创建、修改和销毁基础资源；Terraform设置：配置文件，镜像仓库，插件缓存；项目中指定使用本地仓库</p>">
        <!-- OG Tags -->
<meta property="og:url" content="/terraform-how-to.html"/>
<meta property="og:title" content="来玩魔王的咚 | Terraform 基本用法" />
<meta property="og:description" content="<p>Terraform的基本使用：创建、修改和销毁基础资源；Terraform设置：配置文件，镜像仓库，插件缓存；项目中指定使用本地仓库</p>" />
        <!-- favicon -->
        <link rel="icon" type="image/png" href="/images/mowang.png">
        <!-- moment.js for date formatting -->
        <script src="/theme/js/moment.js"></script>
        <!-- css -->
        <link rel="stylesheet" type="text/css" href="/theme/css/main.css" />
        <!-- 左边的menu，如果页面高度不够，就跟着滚动，否则文章分类显示不全 -->
        <link rel="stylesheet" type="text/css" href="/theme/css/mycss/menu.css" />
		<script>
			
                /*! grunt-grunticon Stylesheet Loader - v2.1.2 | https://github.com/filamentgroup/grunticon | (c) 2015 Scott Jehl, Filament Group, Inc. | MIT license. */
    
    (function(e){function t(t,n,r,o){"use strict";function a(){for(var e,n=0;u.length>n;n++)u[n].href&&u[n].href.indexOf(t)>-1&&(e=!0);e?i.media=r||"all":setTimeout(a)}var i=e.document.createElement("link"),l=n||e.document.getElementsByTagName("script")[0],u=e.document.styleSheets;return i.rel="stylesheet",i.href=t,i.media="only x",i.onload=o||null,l.parentNode.insertBefore(i,l),a(),i}var n=function(r,o){"use strict";if(r&&3===r.length){var a=e.navigator,i=e.Image,l=!(!document.createElementNS||!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect||!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1")||e.opera&&-1===a.userAgent.indexOf("Chrome")||-1!==a.userAgent.indexOf("Series40")),u=new i;u.onerror=function(){n.method="png",n.href=r[2],t(r[2])},u.onload=function(){var e=1===u.width&&1===u.height,a=r[e&&l?0:e?1:2];n.method=e&&l?"svg":e?"datapng":"png",n.href=a,t(a,null,null,o)},u.src="",document.documentElement.className+=" grunticon"}};n.loadCSS=t,e.grunticon=n})(this);(function(e,t){"use strict";var n=t.document,r="grunticon:",o=function(e){if(n.attachEvent?"complete"===n.readyState:"loading"!==n.readyState)e();else{var t=!1;n.addEventListener("readystatechange",function(){t||(t=!0,e())},!1)}},a=function(e){return t.document.querySelector('link[href$="'+e+'"]')},c=function(e){var t,n,o,a,c,i,u={};if(t=e.sheet,!t)return u;n=t.cssRules?t.cssRules:t.rules;for(var l=0;n.length>l;l++)o=n[l].cssText,a=r+n[l].selectorText,c=o.split(");")[0].match(/US\-ASCII\,([^"']+)/),c&&c[1]&&(i=decodeURIComponent(c[1]),u[a]=i);return u},i=function(e){var t,o,a;o="data-grunticon-embed";for(var c in e)if(a=c.slice(r.length),t=n.querySelectorAll(a+"["+o+"]"),t.length)for(var i=0;t.length>i;i++)t[i].innerHTML=e[c],t[i].style.backgroundImage="none",t[i].removeAttribute(o);return t},u=function(t){"svg"===e.method&&o(function(){i(c(a(e.href))),"function"==typeof t&&t()})};e.embedIcons=i,e.getCSS=a,e.getIcons=c,e.ready=o,e.svgLoadedCallback=u,e.embedSVG=u})(grunticon,this);
                
                grunticon(["/theme/css/icons.data.svg.css", "/theme/css/icons.data.png.css", "/theme/css/icons.fallback.css"]);
            </script>
        <noscript><link href="/theme/css/icons.fallback.css" rel="stylesheet"></noscript>
        <!-- menu toggle javascript -->
        <script type="text/javascript">
            document.addEventListener("DOMContentLoaded", initMenu);
            
            function initMenu(){
                var menu = document.getElementById("menu");
                var menulink = document.getElementById("menu-link");
                menulink.addEventListener("click", function toggleMenu(){
                        window.event.preventDefault();
                        menulink.classList.toggle('active');
                        menu.classList.toggle('active');              
                    });
            };
        </script>
        <!-- 不蒜子 -->
        <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

    <meta name="description" content="<p>Terraform的基本使用：创建、修改和销毁基础资源；Terraform设置：配置文件，镜像仓库，插件缓存；项目中指定使用本地仓库</p>" />

    <meta name="tags" content="terraform" />
  <!-- 替换部分base的样式，看文章时，要再宽一点，右边有很多空间可以撑开 -->
  <link rel="stylesheet" type="text/css" href="/theme/css/mycss/article.css" />

</head>
<body>
    <div role="banner" id="masthead">
        <header>
            <a href="/"><img src="/images/mowang.png" alt="McManus Logo"></a>
                <h1>来玩魔王的咚@骑士救兵</h1>
            <a href="#menu" id="menu-link">more stuff</a>
            <nav id="menu">
                <ul>
                        <li><a href="/tags">tags</a></li>
                            <li class="active"><a href="/category/cloud.html">Cloud</a></li>
                            <li><a href="/category/docker.html">Docker</a></li>
                            <li><a href="/category/go.html">Go</a></li>
                            <li><a href="/category/linux.html">Linux</a></li>
                            <li><a href="/category/python.html">Python</a></li>
                            <li><a href="/category/xue-xi-bi-ji.html">学习笔记</a></li>
                            <li><a href="/category/yun-wei-zi-dong-hua.html">运维自动化</a></li>
                </ul>
            </nav>
        </header>
    </div>
        <div class="page" role="main">
  <div class="article" role="article">
    <article>
        <footer>
            <a name="top"></a>
            <p>
              <time datetime=" 2021-05-01 16:00:00+08:00">
                <script>document.write(moment('2021-05-01 16:00:00+08:00').format('LL'));</script>
              </time>
              ~
              <time datetime=" 2021-05-01 16:00:00+08:00">
                <script>document.write(moment('2021-05-06 13:00:00+08:00').format('LL'));</script>
              </time>
            </p>
        </footer>
        <header>
          <h2>
            Terraform 基本用法
          </h2>
        </header>
      <div class="content">
         <div class="toc">
<ul>
<li><a href="#qian-ti-zhun-bei">前提准备</a><ul>
<li><a href="#an-zhuang-terraform">安装 Terraform</a></li>
<li><a href="#azure-cli-deng-lu">Azure CLI 登录</a></li>
</ul>
</li>
<li><a href="#chuang-jian-ji-chu-zi-yuan">创建基础资源</a><ul>
<li><a href="#import-dao-ru-zi-yuan-xin-xi">import 导入资源信息</a></li>
</ul>
</li>
<li><a href="#xiu-gai-ji-chu-zi-yuan">修改基础资源</a><ul>
<li><a href="#xiu-gai-yi-you-de-zi-yuan">修改已有的资源</a></li>
<li><a href="#cha-kan-zhuang-tai-wen-jian">查看状态文件</a></li>
</ul>
</li>
<li><a href="#xiao-hui-ji-chu-zi-yuan">销毁基础资源</a><ul>
<li><a href="#dan-du-zhi-ding-yao-xiao-hui-de-zi-yuan">单独指定要销毁的资源</a></li>
</ul>
</li>
<li><a href="#terraform-cli-she-zhi">Terraform CLI 设置</a><ul>
<li><a href="#pei-zhi-wen-jian-wei-zhi">配置文件位置</a></li>
<li><a href="#shi-yong-ben-di-jing-xiang-cang-ku">使用本地镜像仓库</a></li>
<li><a href="#shi-yong-mo-ren-de-ben-di-jing-xiang-cang-ku">使用默认的本地镜像仓库</a></li>
<li><a href="#she-zhi-shi-yong-huan-cun">设置使用缓存</a></li>
<li><a href="#zai-xiang-mu-zhong-zhi-ding-provider">在项目中指定 provider</a></li>
</ul>
</li>
</ul>
</div>
<h3 id="qian-ti-zhun-bei"><a class="toclink" href="#qian-ti-zhun-bei">前提准备</a></h3>
<p>在Azure平台上创建、修改、销毁基础资源。参考下面的官方文档：<br>
<a href="https://learn.hashicorp.com/collections/terraform/azure-get-started">https://learn.hashicorp.com/collections/terraform/azure-get-started</a>  </p>
<h4 id="an-zhuang-terraform"><a class="toclink" href="#an-zhuang-terraform">安装 Terraform</a></h4>
<p>安装Terraform，可以参考官方的文档：<br>
<a href="https://learn.hashicorp.com/tutorials/terraform/install-cli?in=terraform/azure-get-started#install-terraform">https://learn.hashicorp.com/tutorials/terraform/install-cli?in=terraform/azure-get-started#install-terraform</a><br>
安装后验证一下：</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>terraform --version
<span class="go">Terraform v0.15.1</span>
<span class="go">on linux_amd64</span>
<span class="gp">$ </span>
</code></pre></div>

<h4 id="azure-cli-deng-lu"><a class="toclink" href="#azure-cli-deng-lu">Azure CLI 登录</a></h4>
<p>Terraform 需要使用 Azure 的身份验证，操作前需要先登录。  </p>
<h5 id="an-zhuang"><a class="toclink" href="#an-zhuang">安装</a></h5>
<p>下面是微软的关于安装的文档：<br>
<a href="https://docs.azure.cn/zh-cn/cli/install-azure-cli?view=azure-cli-latest">https://docs.azure.cn/zh-cn/cli/install-azure-cli?view=azure-cli-latest</a>  </p>
<h5 id="qie-huan-yun-qu-yu"><a class="toclink" href="#qie-huan-yun-qu-yu">切换云区域</a></h5>
<p>登录时确保云区域设置正确：</p>
<div class="highlight"><pre><span></span><code><span class="c1"># 切换到中国区</span>
az cloud <span class="nb">set</span> -n AzureChinaCloud
<span class="c1"># 切换到国际区</span>
az cloud <span class="nb">set</span> -n AzureCloud
</code></pre></div>

<h5 id="deng-lu-ren-zheng"><a class="toclink" href="#deng-lu-ren-zheng">登录认证</a></h5>
<p>命令执行后，会自动打开浏览器，在浏览器中完成登录后，会打印一些登录的信息。<br>
具体如下：</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>az login
<span class="go">The default web browser has been opened at https://login.microsoftonline.com/common/oauth2/authorize. Please continue th</span>
<span class="go">e login in the web browser. If no web browser is available or if the web browser fails to open, use device code flow wit</span>
<span class="go">h `az login --use-device-code`.</span>
<span class="go">You have logged in. Now let us find all the subscriptions to which you have access...</span>
<span class="go">The following tenants don&#39;t contain accessible subscriptions. Use &#39;az login --allow-no-subscriptions&#39; to have tenant lev</span>
<span class="go">el access.</span>
<span class="go">xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx &#39;默认目录&#39;</span>
<span class="go">[</span>
<span class="go">  {</span>
<span class="go">    &quot;cloudName&quot;: &quot;AzureCloud&quot;,</span>
<span class="go">    &quot;homeTenantId&quot;: &quot;xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx&quot;,</span>
<span class="go">    &quot;id&quot;: &quot;xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx&quot;,</span>
<span class="go">    &quot;isDefault&quot;: true,</span>
<span class="go">    &quot;managedByTenants&quot;: [],</span>
<span class="go">    &quot;name&quot;: &quot;订阅名称&quot;,</span>
<span class="go">    &quot;state&quot;: &quot;Enabled&quot;,</span>
<span class="go">    &quot;tenantId&quot;: &quot;xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx&quot;,</span>
<span class="go">    &quot;user&quot;: {</span>
<span class="go">      &quot;name&quot;: &quot;your-username@domain.com&quot;,</span>
<span class="go">      &quot;type&quot;: &quot;user&quot;</span>
<span class="go">    }</span>
<span class="go">  }</span>
<span class="go">]</span>
<span class="gp">$ </span>
</code></pre></div>

<h3 id="chuang-jian-ji-chu-zi-yuan"><a class="toclink" href="#chuang-jian-ji-chu-zi-yuan">创建基础资源</a></h3>
<p>先只操作资源组，会完成资源组的创建、修改和销毁。不会对别的资源进行操作。<br>
首先，创建一个文件夹，作为项目目录：</p>
<div class="highlight"><pre><span></span><code>mkdir learn-terraform-azure <span class="o">&amp;&amp;</span> <span class="nb">cd</span> <span class="nv">$_</span>
</code></pre></div>

<p>在项目目录下创建<code>main.tf</code>文件，内容如下：</p>
<div class="highlight"><pre><span></span><code><span class="c1"># Configure the Azure provider</span>
<span class="nb">terraform</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">  </span><span class="nb">required_providers</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nb">azurerm</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">      </span><span class="na">source</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;hashicorp/azurerm&quot;</span><span class="w"></span>
<span class="w">      </span><span class="na">version</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;&gt;= 2.26&quot;</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">  </span><span class="p">}</span><span class="w"></span>

<span class="w">  </span><span class="na">required_version</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;&gt;= 0.14.9&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kr">provider</span><span class="w"> </span><span class="nv">&quot;azurerm&quot;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">  </span><span class="nb">features</span><span class="w"> </span><span class="p">{}</span><span class="c1"></span>
<span class="c1">  # 我的环境需要加上下面的设置</span>
<span class="w">  </span><span class="na">skip_provider_registration</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="no">true</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kr">resource</span><span class="w"> </span><span class="nc">&quot;azurerm_resource_group&quot;</span><span class="w"> </span><span class="nv">&quot;rg&quot;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">  </span><span class="na">name</span><span class="w">     </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;myTFResourceGroup&quot;</span><span class="w"></span>
<span class="w">  </span><span class="na">location</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;westus2&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>最上面的terraform块不是必须的，很多其他的入门文档中都没有这段设置。  </p>
<p>初始化：</p>
<div class="highlight"><pre><span></span><code>terraform init
</code></pre></div>

<p>在文件夹中下载安装独立的插件。  </p>
<p>生成执行计划：</p>
<div class="highlight"><pre><span></span><code>terraform plan
</code></pre></div>

<p>第一次并不能运行，会报错，同时也是提示信息。<br>
按照提示，在provider中加上<code>skip_provider_registration = true</code>才能成功执行。  </p>
<p>应用配置：</p>
<div class="highlight"><pre><span></span><code>terraform apply
</code></pre></div>

<p>会先跑一遍plan，打出出对资源的修改。然后等待输入yes确认后开始实施。  </p>
<h4 id="import-dao-ru-zi-yuan-xin-xi"><a class="toclink" href="#import-dao-ru-zi-yuan-xin-xi">import 导入资源信息</a></h4>
<p>如果资源组并不是用terraform创建的，而是已经存在的资源组。则可以通过import来导入已有的资源信息。<br>
配置文件中，要引入需要导入的资源：</p>
<div class="highlight"><pre><span></span><code><span class="n">provider</span><span class="w"> </span><span class="s">&quot;azurerm&quot;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">  </span><span class="n">features</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>
<span class="w">  </span><span class="p">#</span><span class="w"> </span><span class="err">我的环境需要加上下面的设置</span><span class="w"></span>
<span class="w">  </span><span class="n">skip_provider_registration</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">true</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="n">resource</span><span class="w"> </span><span class="s">&quot;azurerm_resource_group&quot;</span><span class="w"> </span><span class="s">&quot;rg&quot;</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>
</code></pre></div>

<p><code>resource "azurerm_resource_group" "rg"</code>里的内容填不填都没有关系，但是一定要引入这个资源。  </p>
<p>然后，还需要有这个资源的ID，然后用下面的命令导入：</p>
<div class="highlight"><pre><span></span><code>terraform import azurerm_resource_group.rg <span class="si">${</span><span class="nv">资源</span><span class="p"> ID</span><span class="si">}</span>
</code></pre></div>

<p>使用import应该可以导入任何资源，只要有资源的ID。<br>
不仅仅是从无到有的导入，这实际是资源信息的同步。如果中间有不通过terraform对资源进行过更改，也可以用import同步资源的最新状态。  </p>
<h3 id="xiu-gai-ji-chu-zi-yuan"><a class="toclink" href="#xiu-gai-ji-chu-zi-yuan">修改基础资源</a></h3>
<p>修改资源组，加上tag标签，配置文件如下：</p>
<div class="highlight"><pre><span></span><code>resource &quot;azurerm_resource_group&quot; &quot;rg&quot; {
    name     = &quot;myTFResourceGroup&quot;
    location = &quot;westus2&quot;

    tags = {
        Environment = &quot;Terraform Getting Started&quot;
        Team = &quot;DevOps&quot;
    }
}
</code></pre></div>

<p>不用初始化了，在创建的时候已经有了。不过重复执行命令也不会重复操作。<br>
生成执行计划，这次加上-out参数：</p>
<div class="highlight"><pre><span></span><code>terraform plan -out<span class="o">=</span>newplan
</code></pre></div>

<p>参数提供的文件名，加上参数后，会生成一个二进制文件，保存的是plan的内容。之后可以使用。  </p>
<p>应用配置，使用已有的plan文件：</p>
<div class="highlight"><pre><span></span><code>terraform apply <span class="s2">&quot;newplan&quot;</span>
</code></pre></div>

<p>这次指定了plan文件，之前未指定的情况下，会重新跑一遍plan，然后等待用户yes确认。<br>
这次已经有之前保存的plan了，就会跳过plan，也会跳过交互的确认，直接就会实施对资源的变更。  </p>
<h4 id="xiu-gai-yi-you-de-zi-yuan"><a class="toclink" href="#xiu-gai-yi-you-de-zi-yuan">修改已有的资源</a></h4>
<p>如果跳过了上面资源组的创建，比如资源组之前已经通过Portal创建好了。再要想直接想对资源组进行修改，也就是加上tag标签，需要额外的步骤。<br>
如果仅仅是在配置文件中，填好一样的name和location，然后再加上需要修改的tag的配置，运行plan的结果，你会看到整个资源都是加号，也就表示不仅tag要创建，整个资源都需要被创建。这是如果运行apply，会尝试新建一个资源组，然后由于不能有重复的name，最后会提示创建失败。<br>
正确的情况是，只有tag属性前有加号，这个表示要新建的，已有的资源和属性前是没有加号的。这也是通过plan我们需要确认的重要信息。<br>
原因是tarraform的状态文件，新建资源成功后，会在本地创建状态文件。这次修改资源，会对比本地的状态文件，找到需要变动的配置，生成plan。本地没有状态文件，就会被认为资源不存在。所以整个资源都会被认为需要新建。<br>
原因就是没有状态文件，或者状态文件不同步。那么只要用<code>terraform import</code>同步到最新的资源状态，问题就能解决。<br>
当然，本地的状态文件和云端最新的资源状态不同步，也会有问题。一般就是建议完全用terraform对资源进行管理。当然，如果无法做到，或者不确定，那么就需要运行plan前同步资源状态。  </p>
<h4 id="cha-kan-zhuang-tai-wen-jian"><a class="toclink" href="#cha-kan-zhuang-tai-wen-jian">查看状态文件</a></h4>
<p>状态文件是JSON格式的，文件名是terraform.tfstate。不建议直接修改这个文件。不仅是修改，包括查看也建议使用terraform提供的工具。<br>
查看资源状态：</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>terraform show
<span class="gp"># </span>azurerm_resource_group.rg:
<span class="go">resource &quot;azurerm_resource_group&quot; &quot;rg&quot; {</span>
<span class="go">    id       = &quot;/subscriptions/c9ed8610-47a3-4107-a2b2-a322114dfb29/resourceGroups/myTFResourceGroup&quot;</span>
<span class="go">    location = &quot;westus2&quot;</span>
<span class="go">    name     = &quot;myTFResourceGroup&quot;</span>
<span class="go">    tags     = {</span>
<span class="go">        &quot;Environment&quot; = &quot;Terraform Getting Started&quot;</span>
<span class="go">        &quot;Team&quot;        = &quot;DevOps&quot;</span>
<span class="go">    }</span>
<span class="go">}</span>
</code></pre></div>

<p>有一个系列命令<code>erraform state</code>专门用来查看这个状态文件。<br>
查看有哪些资源，如果包含很多资源，这个命令会将资源的名称都列出来：</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>terraform state list
<span class="go">azurerm_resource_group.rg</span>
</code></pre></div>

<p>更多的用法，查看命令帮助：</p>
<div class="highlight"><pre><span></span><code>terraform state
</code></pre></div>

<p>这个系列命令就是专门管理terraform状态的。对于个人使用terraform，仅在本地存放状态文件，只需要其中一小部分功能。<br>
这个工具是支持状态文件远程存储的，在团队协作时很有用。所以好几个子命令暂时都用不上。  </p>
<h3 id="xiao-hui-ji-chu-zi-yuan"><a class="toclink" href="#xiao-hui-ji-chu-zi-yuan">销毁基础资源</a></h3>
<p>最后，销毁资源比较简单，命令如下：</p>
<div class="highlight"><pre><span></span><code>terraform destroy
</code></pre></div>

<p>和applay一样，会有一个plan确认要做哪些更改，然后yes确认操作。  </p>
<p><strong>注意</strong><br>
如果最开始，没有通过terraform创建资源，而是用import导入已有的资源组的状态。<br>
然后在修改资源的时候添加了tag信息，对资源进行了变更。这里也不要执行destroy命令。否则会把你原本就有的资源组给删除了。<br>
要恢复到修改资源组之前的状态，就修改配置文件，再执行一次applay改回去。  </p>
<h4 id="dan-du-zhi-ding-yao-xiao-hui-de-zi-yuan"><a class="toclink" href="#dan-du-zhi-ding-yao-xiao-hui-de-zi-yuan">单独指定要销毁的资源</a></h4>
<p>加上target参数：</p>
<div class="highlight"><pre><span></span><code>$ terraform destroy -target<span class="o">=</span>azurerm_virtual_machine.vm
</code></pre></div>

<p>不过忘记加参数还是会删除掉配置文件中所有的资源，容易出问题，不推荐。<br>
如果指定的资源被其他资源依赖，则会连被依赖的资源也一并删除。很方便，具体看运行后的plan报告。  </p>
<p>用target可以从打配置中，拆分出部分配置，但是这不是官方推荐的方法。官方推荐，将配置分解为多个较小的配置，每个配置都可以独立应用，实现隔离。拆分后要引用配置外的资源，需要再用到Data sources。下面是官方文档，这篇不展开了。<br>
<a href="https://www.terraform.io/docs/language/data-sources/index.html">https://www.terraform.io/docs/language/data-sources/index.html</a>  </p>
<h3 id="terraform-cli-she-zhi"><a class="toclink" href="#terraform-cli-she-zhi">Terraform CLI 设置</a></h3>
<p>terraform还有些参数可以设置：<br>
<a href="https://www.terraform.io/docs/cli/config/index.html">https://www.terraform.io/docs/cli/config/index.html</a><br>
有配置文件的方式：<br>
<a href="https://www.terraform.io/docs/cli/config/config-file.html">https://www.terraform.io/docs/cli/config/config-file.html</a><br>
也可以通过环境变量来设置，不过有些复杂的设置只能写在配置文件里。  </p>
<h4 id="pei-zhi-wen-jian-wei-zhi"><a class="toclink" href="#pei-zhi-wen-jian-wei-zhi">配置文件位置</a></h4>
<p>Linux系统的配置文件，默认是：<code>~/.terraformrc</code>。<br>
可以通过环境变量，修改配置文件的路径和文件名：</p>
<div class="highlight"><pre><span></span><code><span class="nb">export</span> <span class="nv">TF_CLI_CONFIG_FILE</span><span class="o">=</span><span class="s2">&quot;</span><span class="nv">$HOME</span><span class="s2">/.terraformrc-custom&quot;</span>
</code></pre></div>

<h4 id="shi-yong-ben-di-jing-xiang-cang-ku"><a class="toclink" href="#shi-yong-ben-di-jing-xiang-cang-ku">使用本地镜像仓库</a></h4>
<p><em>下面还有默认的本地镜像仓库，用起来更方便，不用设置。如果没有特别的定制需要，用不到这个。</em><br>
在配置文件中设置本地镜像仓库：</p>
<div class="highlight"><pre><span></span><code><span class="nb">provider_installation</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">  </span><span class="nb">filesystem_mirror</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="na">path</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;/usr/share/terraform/providers&quot;</span><span class="w"></span>
<span class="w">    </span><span class="na">include</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;example.com/*/*&quot;</span><span class="p">]</span><span class="w"></span>
<span class="w">  </span><span class="p">}</span><span class="w"></span>
<span class="w">  </span><span class="nb">direct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="na">exclude</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;example.com/*/*&quot;</span><span class="p">]</span><span class="w"></span>
<span class="w">  </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>include和exclude完整的查找路径分3段，也就是两个斜杠：</p>
<ul>
<li>没有斜杠，只有一段地址不是合法的格式</li>
<li>可以只有一个斜杠，就是2段，那么就是省略第一段。默认就是<code>registry.terraform.io</code></li>
<li>完整的写路径要写3段，也就是两个斜杠</li>
<li><code>*/*</code>不是任意路径，而是官方仓库内的任意路径，也就是<code>registry.terraform.io/*/*</code></li>
<li>任意路径是三个星号：<code>*/*/*</code></li>
</ul>
<p>我的配置（最终我选择不使用这个设置）：</p>
<div class="highlight"><pre><span></span><code><span class="nb">provider_installation</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">  </span><span class="nb">filesystem_mirror</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="na">path</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;/workspaces/azure-terraform/.terraform.d/providers&quot;</span><span class="w"></span>
<span class="w">    </span><span class="na">include</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;kreuzwerker/docker&quot;, &quot;hashicorp/azurerm&quot;</span><span class="p">]</span><span class="w"></span>
<span class="w">  </span><span class="p">}</span><span class="w"></span>
<span class="w">  </span><span class="nb">direct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="na">exclude</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;kreuzwerker/docker&quot;, &quot;hashicorp/azurerm&quot;</span><span class="p">]</span><span class="w"></span>
<span class="w">  </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>如果定义了provider_installation，就完全按照这里的规则下载插件。如果规则有问题，就会报告找不到插件。  </p>
<ul>
<li>include写明确，本地有一个，就写一个。应该不会用到很多，可以写死。使用通配符会出现本地没有的插件也会落在本地的规则里</li>
<li>写一个和include一个的exclude规则，指定使用direct。这样保证本地没有指定的插件可以去官方镜像下载</li>
</ul>
<p>如果不设置provider_installation，还会有默认的本地镜像位置，好处是不用写配置和规则。用默认的应该更方便。  </p>
<h4 id="shi-yong-mo-ren-de-ben-di-jing-xiang-cang-ku"><a class="toclink" href="#shi-yong-mo-ren-de-ben-di-jing-xiang-cang-ku">使用默认的本地镜像仓库</a></h4>
<p>默认的本地镜像仓库不用设置，只要在terraform启动是文件夹存在：</p>
<ul>
<li><code>$HOME/.terraform.d/plugins/</code></li>
<li><code>~/.local/share/terraform/plugins</code></li>
<li><code>/usr/local/share/terraform/plugins</code></li>
<li><code>/usr/share/terraform/plugins</code></li>
</ul>
<p>每一个都会生效，可以存在多个。  </p>
<p>规则也是自动的，direct块的规则会自动生成。仓库里有的就直接从仓库里下。仓库里没有的，还是去官方仓库下。<br>
本地的仓库可以解决网络不通的问题，如果是网络部稳定，可以只启用缓存解决。  </p>
<h4 id="she-zhi-shi-yong-huan-cun"><a class="toclink" href="#she-zhi-shi-yong-huan-cun">设置使用缓存</a></h4>
<p>使用缓存可以避免重复下载插件。另外，即使是本地镜像仓库，也是会缓存的。<br>
使用缓存仍然需要去仓库获取插件的信息和版本，如果是官方仓库，仍然需要联网。这样，如果有新的插件版本，不会继续使用本地缓存的旧版本。<br>
最后插件的下载会使用缓存的副本。  </p>
<p>配置文件开启缓存：</p>
<div class="highlight"><pre><span></span><code>plugin_cache_dir   = &quot;$HOME/.terraform.d/plugin-cache&quot;
</code></pre></div>

<p>使用环境变量开启缓存：</p>
<div class="highlight"><pre><span></span><code><span class="nb">export</span> <span class="nv">TF_PLUGIN_CACHE_DIR</span><span class="o">=</span><span class="s2">&quot;</span><span class="nv">$HOME</span><span class="s2">/.terraform.d/plugin-cache&quot;</span>
</code></pre></div>

<h4 id="zai-xiang-mu-zhong-zhi-ding-provider"><a class="toclink" href="#zai-xiang-mu-zhong-zhi-ding-provider">在项目中指定 provider</a></h4>
<p>这不是terraform的设置，上面是通过全局的设置，解决网络问题导致无法下载插件的问题。<br>
这里是在项目中指定的做法。就是在main.tf配置文件里区分远程和本地仓库。  </p>
<p>下面的设置在main.tf中不是必须的，不写会使用默认设置，这里写的也是默认值：</p>
<div class="highlight"><pre><span></span><code><span class="nb">terraform</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">  </span><span class="nb">required_providers</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nb">azurerm</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">      </span><span class="na">source</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;hashicorp/azurerm&quot;</span><span class="w"></span>
<span class="w">      </span><span class="na">version</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;&gt;= 2.26&quot;</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">  </span><span class="p">}</span><span class="w"></span>

<span class="w">  </span><span class="na">required_version</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;&gt;= 0.14.9&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>主要是source，这里配的是默认值。<br>
这里的source只有2段，缺省了registry.terraform.io，也就是官方仓库。如果有本地镜像，先查找本地的镜像的<code>registry.terraform.io/hashicorp/azurerm</code>，然后再去官方仓库<code>registry.terraform.io/hashicorp/azurerm</code>找。  </p>
<h5 id="she-zhi-shi-yong-ben-di-cang-ku"><a class="toclink" href="#she-zhi-shi-yong-ben-di-cang-ku">设置使用本地仓库</a></h5>
<p>在本地仓库目录里建立一个专门的文件夹，比如local-registry。如果是默认的本地仓库，那么完整的文件夹路径就是<code>$HOME/.terraform.d/plugins/local-registry</code>。<br>
然后<code>source = "local-registry/hashicorp/azurerm"</code>，这样就只会在本地找了。<br>
除非namespace能找到叫local-registry的主机。  </p>
      </div>
      <div class="back-to-top">
        <a href="/">HOME</a>
        <a href="#top">TOP</a>
      </div>
    </article>
  </div>
<!-- end article -->
<!-- 页面往下滚动一段之后才会显示TOC -->
<script>
  window.onscroll = function() {
    var tocbox = document.getElementsByClassName('toc')[0];
    var osTop = document.documentElement.scrollTop || document.body.scrollTop;
    var osWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
    // console.log(osTop)
    if (osTop>300 && osWidth>865) {
      tocbox.style.display = "block"
    }
    if (osTop<300 || osWidth<865) {
      tocbox.style.display = "none"
    }
  }
</script>
                <footer>
                    <div class="icons">
                    </div>
                    <span id="busuanzi_container_page_pv" style="padding: 10px">本文阅读量<span id="busuanzi_value_page_pv"></span>次</span>
                    <span id="busuanzi_container_site_pv" style="padding: 10px">本站总访问量<span id="busuanzi_value_site_pv"></span>次</span>
                    <span id="busuanzi_container_site_uv" style="padding: 10px">本站总访客数<span id="busuanzi_value_site_uv"></span>人</span>
                    <p>© <script>document.write(moment().format('YYYY'));</script> 749B</p>
                </footer>
        </div>
</body>
</html>